/**
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import type common from '@ohos.app.ability.common';
import BaseModel from '../../../../../../../common/utils/src/main/ets/default/model/BaseModel';
import LogUtil from '../../../../../../../common/utils/src/main/ets/default/baseUtil/LogUtil';
import vpn from '@ohos.net.vpn';
import StateModel from './StateModel';
import VpnConfig from './VpnConfig';
import { BusinessError, emitter } from '@kit.BasicServicesKit';


const MODULE_TAG: string = 'setting_vpn:VpnModel:';

/**
 *  emitter event
 */
export enum EventId {
  VPN_QUERY = 'VPN_QUERY',
  VPN_LIST = 'VPN_LIST',
  SHOWERROR = 'SHOWERROR'
}

/**
 * app management service class
 */
class VpnModel extends BaseModel {
  connection: vpn.VpnConnection | undefined = undefined;
  timeoutId:number;
  init(context: common.UIAbilityContext) {
    this.connection = vpn.createVpnConnection(context);
    try {
      LogUtil.info(MODULE_TAG + `vpnConnection on subscribe start`);
      // @ts-ignore
      this.connection?.on('connect', (data) => {
        this.removeTimeout();
        LogUtil.info(MODULE_TAG + `vpnConnection on subscribe data = ${JSON.stringify(data)} `);
        if (data?.isConnected) {
          this.setConnectState(StateModel.connectSuccess);
        } else {
          this.setConnectState(StateModel.connectNot, -1);
          this.destroy();
        }
      })
    } catch (error) {
      LogUtil.info(MODULE_TAG + `vpnConnection on subscribe on error = ${JSON.stringify(error)}`);
    }
    this.getState();
  }

  unInit() {
    try {
      LogUtil.info(MODULE_TAG + `vpnConnection on subscribe off start`);
      // @ts-ignore
      this.connection?.off('connect', (error, data) => {
        LogUtil.info(MODULE_TAG + `vpnConnection on subscribe off = ${JSON.stringify(error)} data = ${data}`);
      })
    } catch (error) {
      LogUtil.info(MODULE_TAG + `vpnConnection on subscribe off error = ${JSON.stringify(error)}`);
    }
  }

  setConnectState(state:number,id?:number){
    let connectState:StateModel = AppStorage.get<StateModel>('connectState');
    if(id) {
      AppStorage.setOrCreate('connectState',new StateModel(id,state));
    } else {
      AppStorage.setOrCreate('connectState',new StateModel(connectState.vpnId,state));
    }
  }

  removeTimeout(){
    if(this.timeoutId) {
      LogUtil.info(MODULE_TAG + `removeTimeout timeoutId = ${this.timeoutId}`);
      clearTimeout(this.timeoutId);
    }
  }

  setUp(vpnConfig: VpnConfig, callback) {
    LogUtil.info(MODULE_TAG + `setUp start`);
    this.removeTimeout();
    this.timeoutId = setTimeout(() => {
      this.setConnectState(StateModel.connectFailed,vpnConfig.id);
      LogUtil.info(MODULE_TAG + `setUp :timeout exec connectFailed}`);
      this.destroy();
    }, 30000);

    try {
      this.setConnectState(StateModel.connectIng,vpnConfig.id);
      this.connection.setUp(vpnConfig, (error, data) => {
        if (error) {
          this.removeTimeout();
          emitter.emit(EventId.SHOWERROR);
          this.setConnectState(StateModel.connectFailed,vpnConfig.id);
          this.destroy();
        } else {
          callback?.();
        }
        LogUtil.info(MODULE_TAG + `setUp error = ${JSON.stringify(error)} data = ${JSON.stringify(data)}`);
      })
    } catch (error) {
      this.removeTimeout();
      this.setConnectState(StateModel.connectFailed,vpnConfig.id);
      this.destroy();
      LogUtil.error(MODULE_TAG + `setUp error3 = ${JSON.stringify(error)}`);
      emitter.emit(EventId.SHOWERROR);
    }
  }

  getState() {
    try {
      LogUtil.info(MODULE_TAG + `getState start`);
      // @ts-ignore
      this.connection?.getState((error, data: number) => {
        let currentConnectVpnId = AppStorage.get<StateModel>('connectState')?.vpnId;
        LogUtil.info(MODULE_TAG + `getState = ${JSON.stringify(error)} data = ${JSON.stringify(data)}  currentConnectVpnId = ${currentConnectVpnId}`);
        if (currentConnectVpnId != -1) {
          if (data == 0) {
            this.setConnectState(StateModel.connectNot,-1);
            this.destroy();
          } else if (data == 1) {
            this.setConnectState(StateModel.connectSuccess);
          } else if (data == 2) {
            this.setConnectState(StateModel.connectFailed);
            this.destroy();
          }
        }
      })
    } catch (error) {
      LogUtil.error(MODULE_TAG + `getState error = ${JSON.stringify(error)}`);
    }
  }

  destroy(callback?) {
    this.connection?.destroy((error: BusinessError) => {
      LogUtil.info(MODULE_TAG + `destroy error = ${JSON.stringify(error)}`);
      if (error) {
      //  promptAction.showToast({ message: `destroy error = ${JSON.stringify(error)}` })
      } else {
      }
      callback?.();
    });
  }

  uint8ArrayToString(u8a: Uint8Array) {
    let dataStr = "";
    for (let i = 0; i < u8a.length; i++) {
      dataStr += String.fromCharCode(u8a[i])
    }
    return dataStr;
  }
}

let vpnModel = new VpnModel();

export default vpnModel;